/*
Copyright (C) 1996-1997 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/
// r_efrag.c

#include "quakedef.h"


/*
===============================================================================

					ENTITY FRAGMENT FUNCTIONS

===============================================================================
*/

efrag_t		**lastlink;


/*
===================
R_SplitEntityOnNode
===================
*/
void R_SplitEntityOnNode (mnode_t *node, entity_t *ent, float *mins, float *maxs)
{
	if (node->contents == CONTENTS_SOLID)
		return;

	// add an efrag if the node is a leaf
	if (node->contents < 0)
	{
		mleaf_t *leaf = (mleaf_t *) node;
		efrag_t *ef = (efrag_t *) mapPool->Alloc (sizeof (efrag_t));

		ef->entity = ent;

		// add the entity link
		*lastlink = ef;
		lastlink = &ef->entnext;
		ef->entnext = NULL;

		// set the leaf links
		ef->leaf = leaf;
		ef->leafnext = leaf->efrags;
		leaf->efrags = ef;

		return;
	}

	// NODE_MIXED
	mplane_t *splitplane = node->plane;
	int sides = BoxOnPlaneSide (mins, maxs, splitplane);

	// recurse down the contacted sides
	if (sides & 1) R_SplitEntityOnNode (node->children[0], ent, mins, maxs);
	if (sides & 2) R_SplitEntityOnNode (node->children[1], ent, mins, maxs);
}


/*
===========
R_AddEfrags
===========
*/
void R_AddEfrags (entity_t *ent)
{
	model_t	*entmodel;
	vec3_t	r_emins, r_emaxs;

	if (!ent->model)
		return;

	lastlink = &ent->efrag;
	entmodel = ent->model;

	for (int i = 0; i < 3; i++)
	{
		r_emins[i] = ent->origin[i] + entmodel->mins[i];
		r_emaxs[i] = ent->origin[i] + entmodel->maxs[i];
	}

	R_SplitEntityOnNode (cl.worldmodel->nodes, ent, r_emins, r_emaxs);
}


/*
================
R_StoreEfrags

// FIXME: a lot of this goes away with edge-based
================
*/
void R_StoreEfrags (efrag_t **ppefrag)
{
	efrag_t *pefrag;

	while ((pefrag = *ppefrag) != NULL)
	{
		entity_t *pent = pefrag->entity;
		model_t *clmodel = pent->model;

		switch (clmodel->type)
		{
		case mod_alias:
		case mod_brush:
		case mod_sprite:
			pent = pefrag->entity;

			// using the copied off list so this can be safely called multiple times between calls to CL_RelinkEntities
			if ((pent->visframe != ref.FrameCount) && (r_numvisedicts < MAX_VISEDICTS))
			{
				// if it wasn't on the previous frame reset it fully
				if (pent->visframe != (ref.FrameCount - 1))
				{
					CL_ClearRocketTrail (pent);
					pent->lerpflags |= LERP_RESETALL;
				}
				else pent->lerpflags |= LERP_RESETMOVE;

				r_visedicts[r_numvisedicts++] = pent;

				// mark that we've recorded this entity for this frame
				pent->visframe = ref.FrameCount;
			}

			ppefrag = &pefrag->leafnext;
			break;

		default:
			Sys_Error ("R_StoreEfrags: Bad entity type %d\n", clmodel->type);
		}
	}
}


